JSON 是目前常使用的資料格式之一,而 PostgreSQL 提供了兩種儲存 JSON 的資料型態,一個是 json ,一個是 jsonb 。
json 和 jsonb 這兩種格式的主要差別在於, json 會儲存原始的 JSON 字串, jsonb 會儲存解析過且轉成二進位格式的 JSON 。jsonb 因為需要解析和轉格式,在 INSERT 的時候速度會比 json 慢,但也因為解析過了,所以在查詢的時候,效能會比 json 好。
另外, jsonb 因為會把欄位是 number 型別的轉換成 PostgreSQL 的 numeric 型別(如下面圖片),所以格式和資料合法性的檢查會比 json 嚴謹。
也因為這樣, jsonb 會拒絕超出 numeric 範圍的數字,但 json 不會,如下面的範例。
CREATE TABLE test_numbers (
js JSON,
jsb JSONB
);
-- JSON 欄位可以成功
INSERT INTO test_numbers (js) VALUES ('{"big_num": 1e1000000000}'); -- 成功
-- JSONB 欄位會報錯
INSERT INTO test_numbers (jsb) VALUES ('{"big_num": 1e1000000000}');
-- 會出現錯誤訊息,例如:
-- ERROR: value overflows numeric format
在索引這一塊, jsonb 的支援比較好, jsonb 可以使用 GIN 這個索引,針對 JSON 中的其中一個欄位去做查詢, json 只能使用 BTRee 和 hash ,但這兩個索引僅拿「整個 JSON 字串」做比對,這對查詢的效能和應用上沒有太大幫助。
而 jsonb 之所以支援 GIN 這個索引,是因為 jsonb 可以使用 @> 和 @? 這類的運算子進行查詢( json 不支援),而 GIN 有支援這些運算子,所以 jsonb 可以使用 GIN 這個索引進行優化。
CREATE TABLE test_json (
id SERIAL PRIMARY KEY,
data_json JSON,
data_jsonb JSONB
);
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice", "age": 30}', '{"name": "Alice", "age": 30}');
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice2", "age": 32}', '{"name": "Alice2", "age": 32}');
INSERT INTO test_json (data_json, data_jsonb) VALUES
('{"name": "Alice4", "age": 34}', '{"name": "Alice4", "age": 34}');
以 @> 為例,可以使用 SELECT 的 WHERE 條件去查詢出 jsonb 中的欄位 age 值是32的資料。
如果是 json 的話,PostgreSQL 會噴出錯誤訊息。